//
//  VKTDevice.h
//  VideoKit
//
//  Created by Yusuf Olokoba on 5/15/2023.
//  Copyright © 2023 NatML Inc. All rights reserved.
//

#pragma once

#include <stdbool.h>
#include <stdint.h>
#include <VideoKit/VKTSession.h>

#pragma region --Enumerations--
/*!
 @enum VKTDeviceFlags
 
 @abstract Immutable properties of media devices.
 
 @constant VKT_DEVICE_FLAG_INTERNAL
 Device is internal.

 @constant VKT_DEVICE_FLAG_EXTERNAL
 Device is external.

 @constant VKT_DEVICE_FLAG_DEFAULT
 Device is the default device for its media type.

 @constant VKT_MICROPHONE_FLAG_ECHO_CANCELLATION
 Audio device supports echo cancellation.

 @constant VKT_CAMERA_FLAG_FRONT_FACING
 Camera device is front-facing.

 @constant VKT_CAMERA_FLAG_FLASH
 Camera device supports flash when capturing photos.

 @constant VKT_CAMERA_FLAG_TORCH
 Camera device supports torch.

 @constant VKT_CAMERA_FLAG_DEPTH
 Camera device supports depth streaming.

 @constant VKT_CAMERA_FLAG_EXPOSURE_CONTINUOUS
 Camera device supports continuous auto exposure.

 @constant VKT_CAMERA_FLAG_EXPOSURE_LOCK
 Camera device supports locked auto exposure.

 @constant VKT_CAMERA_FLAG_EXPOSURE_MANUAL
 Camera device supports manual exposure.

 @constant VKT_CAMERA_FLAG_EXPOSURE_POINT
 Camera device supports setting exposure point.

 @constant VKT_CAMERA_FLAG_FOCUS_CONTINUOUS
 Camera device supports continuous auto exposure.

 @constant VKT_CAMERA_FLAG_LOCKED_FOCUS
 Camera device supports locked auto focus.

 @constant VKT_CAMERA_FLAG_FOCUS_POINT
 Camera device supports setting focus point.

 @constant VKT_CAMERA_FLAG_WHITE_BALANCE_CONTINUOUS
 Camera device supports continuous auto white balance.

 @constant VKT_CAMERA_FLAG_WHITE_BALANCE_LOCK
 Camera device supports locked auto white balance.

 @constant VKT_CAMERA_FLAG_VIDEO_STABILIZATION
 Camera device supports video stabilization.
*/
enum VKTDeviceFlags {
    VKT_DEVICE_FLAG_INTERNAL                 = 1 << 0,
    VKT_DEVICE_FLAG_EXTERNAL                 = 1 << 1,
    VKT_DEVICE_FLAG_DEFAULT                  = 1 << 3,
    VKT_MICROPHONE_FLAG_ECHO_CANCELLATION    = 1 << 2,
    VKT_CAMERA_FLAG_FRONT_FACING             = 1 << 6,
    VKT_CAMERA_FLAG_FLASH                    = 1 << 7,
    VKT_CAMERA_FLAG_TORCH                    = 1 << 8,
    VKT_CAMERA_FLAG_DEPTH                    = 1 << 15,
    VKT_CAMERA_FLAG_EXPOSURE_CONTINUOUS      = 1 << 16,
    VKT_CAMERA_FLAG_EXPOSURE_LOCK            = 1 << 11,
    VKT_CAMERA_FLAG_EXPOSURE_MANUAL          = 1 << 14,
    VKT_CAMERA_FLAG_EXPOSURE_POINT           = 1 << 9,
    VKT_CAMERA_FLAG_FOCUS_CONTINUOUS         = 1 << 17,
    VKT_CAMERA_FLAG_FOCUS_LOCK               = 1 << 12,
    VKT_CAMERA_FLAG_FOCUS_POINT              = 1 << 10,
    VKT_CAMERA_FLAG_WHITE_BALANCE_CONTINUOUS = 1 << 18,
    VKT_CAMERA_FLAG_WHITE_BALANCE_LOCK       = 1 << 13,
    VKT_CAMERA_FLAG_VIDEO_STABILIZATION      = 1 << 19,
};
typedef enum VKTDeviceFlags VKTDeviceFlags;

/*!
 @enum VKTDevicePermissionType
 
 @abstract Media device permission type.
 
 @constant VKT_DEVICE_PERMISSION_TYPE_MICROPHONE
 Request microphone permissions.
 
 @constant VKT_DEVICE_PERMISSION_TYPE_CAMERA
 Request camera permissions.
*/
enum VKTDevicePermissionType {
    VKT_DEVICE_PERMISSION_TYPE_MICROPHONE  = 1,
    VKT_DEVICE_PERMISSION_TYPE_CAMERA      = 2,
};
typedef enum VKTDevicePermissionType VKTDevicePermissionType;

/*!
 @enum VKTDevicePermissionStatus
 
 @abstract Media device permission status.
 
 @constant VKT_DEVICE_PERMISSION_STATUS_UNKNOWN
 User has not authorized or denied access to media device.
 
 @constant VKT_DEVICE_PERMISSION_STATUS_DENIED
 User has denied access to media device.

 @constant VKT_DEVICE_PERMISSION_STATUS_AUTHORIZED
 User has authorized access to media device.
*/
enum VKTDevicePermissionStatus {
    VKT_DEVICE_PERMISSION_STATUS_UNKNOWN    = 0,
    VKT_DEVICE_PERMISSION_STATUS_DENIED     = 2,
    VKT_DEVICE_PERMISSION_STATUS_AUTHORIZED = 3,
};
typedef enum VKTDevicePermissionStatus VKTDevicePermissionStatus;
#pragma endregion


#pragma region --Types--
/*!
 @struct VKTDevice
 
 @abstract Media device.

 @discussion Media device.
*/
struct VKTDevice;
typedef struct VKTDevice VKTDevice;

/*!
 @struct VKTSampleBuffer
 
 @abstract Sample buffer generated by a media device.

 @discussion Sample buffer generated by a media device.
*/
struct VKTSampleBuffer;
typedef struct VKTSampleBuffer VKTSampleBuffer;
#pragma endregion


#pragma region --Delegates--
/*!
 @abstract Callback invoked with discovered media devices.
 
 @param context
 User-provided context.
 
 @param devices
 Discovered devices. These MUST be released when they are no longer needed.

 @param count
 Discovered device count.
*/
typedef void (*VKTDeviceDiscoveryHandler) (void* context, VKTDevice** devices, int32_t count);

/*!
 @abstract Callback invoked with new sample buffer from a media device.
 
 @param context
 User-provided context.
 
 @param sampleBuffer
 Sample buffer.
*/
typedef void (*VKTSampleBufferHandler) (void* context, VKTSampleBuffer* sampleBuffer);

/*!
 @abstract Callback invoked when a camera device is disconnected.
 
 @param context
 User-provided context.

 @param device
 Media device that was disconnected.
*/
typedef void (*VKTDeviceDisconnectHandler) (void* context, VKTDevice* device);

/*!
 @abstract Callback invoked with status of a media device permission request.
 
 @param context
 User-provided context.
 
 @param status
 Permission status.
*/
typedef void (*VKTDevicePermissionHandler) (void* context, VKTDevicePermissionStatus status);
#pragma endregion


#pragma region --Client API--
/*!
 @function VKTDeviceRelease

 @abstract Release a media device.

 @discussion Release a media device.

 @param device
 Media device.
*/
VKT_BRIDGE VKT_EXPORT VKTStatus VKT_API VKTDeviceRelease (VKTDevice* device);

/*!
 @function VKTDeviceGetUniqueID

 @abstract Get the media device unique ID.

 @discussion Get the media device unique ID.

 @param device
 Media device.

 @param destination
 Destination UTF-8 string.
*/
VKT_BRIDGE VKT_EXPORT VKTStatus VKT_API VKTDeviceGetUniqueID (
    VKTDevice* device,
    char* destination
);

/*!
 @function VKTDeviceGetName
 
 @abstract Media device name.
 
 @discussion Media device name.
 
 @param device
 Media device.
 
 @param destination
 Destination UTF-8 string.
*/
VKT_BRIDGE VKT_EXPORT VKTStatus VKT_API VKTDeviceGetName (
    VKTDevice* device,
    char* destination
);

/*!
 @function VKTDeviceGetFlags
 
 @abstract Get the media device flags.
 
 @discussion Get the media device flags.
 
 @param device
 Media device.
 
 @returns Device flags.
*/
VKT_BRIDGE VKT_EXPORT VKTDeviceFlags VKT_API VKTDeviceGetFlags (VKTDevice* device);

/*!
 @function VKTDeviceIsRunning
 
 @abstract Is the device running?
 
 @discussion Is the device running?
 
 @param device
 Media device.
 
 @returns True if media device is running.
*/
VKT_BRIDGE VKT_EXPORT bool VKT_API VKTDeviceIsRunning (VKTDevice* device);

/*!
 @function VKTDeviceStartRunning
 
 @abstract Start running an media device.
 
 @discussion Start running an media device.
 
 @param device
 Media device.

 @param sampleBufferHandler
 Sample buffer delegate to receive sample buffers as the device produces them.

 @param context
 User-provided context to be passed to the sample buffer delegate. Can be `NULL`.
*/
VKT_BRIDGE VKT_EXPORT VKTStatus VKT_API VKTDeviceStartRunning (
    VKTDevice* device,
    VKTSampleBufferHandler sampleBufferHandler,
    void* context
);

/*!
 @function VKTDeviceStopRunning
 
 @abstract Stop running device.
 
 @discussion Stop running device.
 
 @param device
 Media device.
*/
VKT_BRIDGE VKT_EXPORT VKTStatus VKT_API VKTDeviceStopRunning (VKTDevice* device);

/*!
 @function VKTDeviceSetDisconnectHandler

 @abstract Set the device disconnect handler.

 @discussion Set the device disconnect handler.
 This provided function pointer is invoked when the device is disconnected.

 @param device
 Media device.

 @param disconnectHandler
 Device disconnect handler. Can be `NULL`.

 @param context
 User-provided context. Can be `NULL`.
*/
VKT_BRIDGE VKT_EXPORT VKTStatus VKT_API VKTDeviceSetDisconnectHandler (
    VKTDevice* device,
    VKTDeviceDisconnectHandler disconnectHandler,
    void* context
);

/*!
 @function VKTDeviceCheckPermissions
 
 @abstract Check permissions for a given media device type.
 
 @discussion Check permissions for a given media device type.
 
 @param type
 Permission type.

 @param request
 Whether to request the permissions if the user has not been asked.
 
 @param handler
 Permission delegate to receive result of permission request.

 @param context
 User-provided context to be passed to the permission delegate. Can be `NULL`.
*/
VKT_BRIDGE VKT_EXPORT VKTStatus VKT_API VKTDeviceCheckPermissions (
    VKTDevicePermissionType type,
    bool request,
    VKTDevicePermissionHandler handler,
    void* context
);
#pragma endregion
